#ifndef AFCORE_DATABASE_DATABASE_DATABASE_QUERY_CALLBACK_
#define AFCORE_DATABASE_DATABASE_DATABASE_QUERY_CALLBACK_

#include <functional>
#include <future>
#include <list>
#include <queue>
#include <utility>

#include "define.h"
#include "database_fwd.h"
#include "nocopyable.h"

namespace afcore {

/// @brief  数据库
namespace database {

/// @brief  查询回调
class AFCORE_DATABASE_API CQueryCallback
  : public CNocopyable {
public:
  /// @brief  构造函数 显示
  /// @param  [RQueryResultFutrue]    result      原生查询结果
  explicit CQueryCallback(RQueryResultFutrue&& result);
  /// @brief  构造函数 显示
  /// @param  [RPreparedQueryResultFutrue]    result      准备语句查询结果
  explicit CQueryCallback(RPreparedQueryResultFutrue && result);
  /// @brief  移动构造函数
  /// @param  that    查询回调
  CQueryCallback(CQueryCallback&& that) noexcept;
  /// @brief  移动赋值函数
  /// @param  that    查询回调
  /// @return 移动后的对象
  CQueryCallback& operator=(CQueryCallback&& that) noexcept;
  /// @param  析构函数
  ~CQueryCallback();

  /// @brief  异步注册回调函数 原始查询 单独
  /// @param  callback        查询回调
  /// @return 查询回调
  CQueryCallback&& WithCallback(std::function<void(RQueryResultSptr)>&& callback);
  /// @brief  异步注册回调函数 准备查询 单独
  /// @param  callback        查询回调
  /// @return 查询回调
  CQueryCallback&& WithPreparedCallback(std::function<void(RPreparedQueryResultSptr)>&& callback);

  /// @brief  异步注册回调函数 原始查询 链式
  /// @param  callback        查询回调
  /// @return 查询回调
  CQueryCallback&& WithChainingCallback(std::function<void(CQueryCallback&, RQueryResultSptr)>&& callback);
  /// @brief  异步注册回调函数 准备查询 链式
  /// @param  callback        查询回调
  /// @return 查询回调
  CQueryCallback&& WithChainingPreparedCallback(std::function<void(CQueryCallback&, RPreparedQueryResultSptr)>&& callback);

  /// @brief  设置下次查询
  /// @param  next            下次查询处理
  void SetNextQuery(CQueryCallback&& next);

  /// @brief  回调状态
  enum EStatus {
    kStatus_NotReady,   ///< 为准备好
    kStatus_NextStep,   ///< 下一步
    kStatus_Completed   ///< 完成
  };

  /// @brief  如果准备好就调用
  EStatus InvokeIfReady();

private:
  template<typename T> friend void ConstructActiveMember(T* obj);
  template<typename T> friend void DestroyActiveMember(T* obj);
  template<typename T> friend void MoveFrom(T* to, T&& from);
private:
  union {
    RQueryResultFutrue string_;           ///< 原生查询
    RPreparedQueryResultFutrue prepared_; ///< 准备查询
  };

  bool is_prepared_ {false}; ///< 准备标识
  struct SQueryCallbackData;
  std::queue<SQueryCallbackData, std::list<SQueryCallbackData>> callbacks_; ///< 回调队列
};

} // !namespace database

} // !namespace afcore

#endif //! AFCORE_DATABASE_DATABASE_DATABASE_QUERY_CALLBACK_